<!--
 * @Author: zzr
 * @Date: 2025-08-18 10:00:56
 * @LastEditors: zzr
 * @Description: 
-->
<template>
  <el-upload
    ref="uploadRef"
    :file-list="normalizedFileList"
    v-bind="mergedAttrs"
    :class="['model-upload', { 'is-disabled': disabled }]"
    :on-change="handleChange"
    :on-remove="handleRemove"
    :before-upload="beforeUpload"
  >
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div class="el-upload__text">将图片拖到此处，或<em>点击上传</em></div>
    <template #tip>
      <div class="el-upload__tip">支持JPG/PNG格式，大小不超过5MB</div>
    </template>
  </el-upload>
</template>

<script setup>
import { ref, computed, watch, useAttrs } from "vue";
import { UploadFilled } from "@element-plus/icons-vue";
import Compressor from "compressorjs";

const props = defineProps({
  modelValue: [Object, Array, String],
  accept: {
    type: String,
    default: "*",
  },
  maxSize: {
    type: Number,
    default: 10,
  },
  limit: {
    type: Number,
    default: 1,
  },
  compress: {
    type: [Boolean, Object],
    default: false,
  },
  disabled: Boolean,
  autoUpload: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(["update:modelValue", "change", "invalid", "success", "error"]);

const attrs = useAttrs();
const uploadRef = ref();
const isLoading = ref(false);

// 合并属性（确保limit优先级）
const mergedAttrs = computed(() => ({
  action: "#",
  autoUpload: props.false,
  showFileList: false,
  ...attrs,
  limit: props.limit,
  accept: props.accept,
  disabled: props.disabled,
}));

const uploadText = computed(() =>
  props.limit > 1 ? `上传文件 (${props.modelValue?.length || 0}/${props.limit})` : "上传文件"
);

const tipText = computed(() => `支持 ${props.accept} 格式，单文件不超过 ${props.maxSize}MB`);

const isMultiple = computed(() => props.limit > 1);
const normalizedFileList = computed(() => {
  return props.modelValue
    ? Array.isArray(props.modelValue)
      ? props.modelValue.map(fileToUploadFile)
      : [fileToUploadFile(props.modelValue)]
    : [];
});

const fileToUploadFile = (file) => {
  return {
    name: file.name,
    size: file.size,
    type: file.type,
    raw: file, // 保留原始文件对象
    url: file.url || URL.createObjectURL(file), // 支持已有URL或生成预览URL
  };
};
const beforeUpload = (file) => {
  // 类型校验
  if (
    props.accept !== "*" &&
    !props.accept
      .split(",")
      .some(
        (ext) =>
          file.name.toLowerCase().endsWith(ext.replace(".", "")) ||
          file.type.includes(ext.replace(".", ""))
      )
  ) {
    emit("invalid", { type: "format", file });
    return false;
  }

  // 大小校验
  if (file.size > props.maxSize * 1024 * 1024) {
    emit("invalid", { type: "size", file });
    return false;
  }

  return true;
};
const handleChange = async (uploadFile, uploadFiles) => {
  try {
    const files = uploadFiles.map((f) => f.raw);

    // 自动压缩处理
    let processedFiles = files;
    if (props.compress && files[0]) {
      processedFiles = await Promise.all(
        files.map((file) => (props.compress ? processCompression(file) : file))
      );
    }

    if (props.autoUpload) {
      isLoading.value = true;
      const res = await submitFiles(processedFiles);
      // 自动上传模式下，更新modelValue为服务器返回的数据
      emit("update:modelValue", isMultiple.value ? res.data : res.data[0]);
      emit("success", res);
    } else {
      // 非自动上传模式，更新文件对象
      const value = isMultiple.value ? processedFiles : processedFiles[0];
      emit("update:modelValue", value);
      emit("change", value);
    }
  } catch (err) {
    emit("error", err);
    throw err;
  } finally {
    isLoading.value = false;
  }
};

const submitFiles = async (files) => {
  if (files.length === 0) {
    throw new Error("请先上传文件");
  }

  const formData = new FormData();
  files.forEach((file) => {
    formData.append(isMultiple.value ? "files[]" : "file", file);
  });

  return await updateFile(formData);
};

const processCompression = (file) => {
  return new Promise((resolve, reject) => {
    new Compressor(file, {
      quality: 0.6,
      ...(typeof props.compress === "object" ? props.compress : {}),
      success(result) {
        resolve(
          new File([result], file.name, {
            type: result.type,
            lastModified: Date.now(),
          })
        );
      },
      error(err) {
        reject(err);
      },
    });
  });
};

const handleRemove = (uploadFile, uploadFiles) => {
  const files = uploadFiles.map((f) => f.raw);
  const value = isMultiple.value ? files : files[0] || null;

  emit("update:modelValue", value);
};

// 暴露方法
defineExpose({
  submit: async () => {
    const files = isMultiple.value ? props.modelValue : props.modelValue ? [props.modelValue] : [];

    if (files.length === 0) {
      throw new Error("请先上传文件");
    }

    const formData = new FormData();
    files.forEach((file) => {
      formData.append("files[]", file);
    });

    try {
      const res = await updateFile(formData);
      emit("success", res);
      return res;
    } catch (err) {
      emit("error", err);
      throw err;
    }
  },
  clear: () => {
    uploadRef.value?.clearFiles();
    emit("update:modelValue", isMultiple.value ? [] : null);
  },
});
</script>
